home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gsshade.c,v 1.3 2000/09/19 19:00:32 lpd Exp $ */
- /* Constructors for shadings */
- #include "gx.h"
- #include "gscspace.h"
- #include "gserrors.h"
- #include "gsstruct.h"
- #include "gxdevcli.h"
- #include "gxcpath.h"
- #include "gxcspace.h"
- #include "gxdcolor.h" /* for filling background rectangle */
- #include "gxistate.h"
- #include "gxpaint.h"
- #include "gxpath.h"
- #include "gxshade.h"
- #include "gzpath.h"
- #include "gzcpath.h"
-
- /* ================ Initialize shadings ================ */
-
- /* ---------------- Generic services ---------------- */
-
- /* GC descriptors */
- private_st_shading();
- private_st_shading_mesh();
-
- /* Check ColorSpace, BBox, and Function (if present). */
- /* Free variables: params. */
- private int
- check_CBFD(const gs_shading_params_t * params,
- const gs_function_t * function, const float *domain, int m)
- {
- int ncomp = gs_color_space_num_components(params->ColorSpace);
-
- if (ncomp < 0 ||
- (params->have_BBox &&
- (params->BBox.p.x > params->BBox.q.x ||
- params->BBox.p.y > params->BBox.q.y))
- )
- return_error(gs_error_rangecheck);
- if (function != 0) {
- if (function->params.m != m || function->params.n != ncomp)
- return_error(gs_error_rangecheck);
- /*
- * The Adobe documentation says that the function's domain must
- * be a superset of the domain defined in the shading dictionary.
- * However, Adobe implementations apparently don't necessarily
- * check this ahead of time; therefore, we do the same.
- */
- #if 0 /*************** */
- {
- int i;
-
- for (i = 0; i < m; ++i)
- if (function->params.Domain[2 * i] > domain[2 * i] ||
- function->params.Domain[2 * i + 1] < domain[2 * i + 1]
- )
- return_error(gs_error_rangecheck);
- }
- #endif /*************** */
- }
- return 0;
- }
-
- /* Check parameters for a mesh shading. */
- private int
- check_mesh(const gs_shading_mesh_params_t * params)
- {
- if (!data_source_is_array(params->DataSource)) {
- int code = check_CBFD((const gs_shading_params_t *)params,
- params->Function, params->Decode, 1);
-
- if (code < 0)
- return code;
- switch (params->BitsPerCoordinate) {
- case 1: case 2: case 4: case 8:
- case 12: case 16: case 24: case 32:
- break;
- default:
- return_error(gs_error_rangecheck);
- }
- switch (params->BitsPerComponent) {
- case 1: case 2: case 4: case 8:
- case 12: case 16:
- break;
- default:
- return_error(gs_error_rangecheck);
- }
- }
- return 0;
- }
-
- /* Check the BitsPerFlag value. Return the value or an error code. */
- private int
- check_BPF(const gs_data_source_t *pds, int bpf)
- {
- if (data_source_is_array(*pds))
- return 2;
- switch (bpf) {
- case 2: case 4: case 8:
- return bpf;
- default:
- return_error(gs_error_rangecheck);
- }
- }
-
- /* Initialize common shading parameters. */
- private void
- shading_params_init(gs_shading_params_t *params)
- {
- params->ColorSpace = 0; /* must be set by client */
- params->Background = 0;
- params->have_BBox = false;
- params->AntiAlias = false;
- }
-
- /* Initialize common mesh shading parameters. */
- private void
- mesh_shading_params_init(gs_shading_mesh_params_t *params)
- {
- shading_params_init((gs_shading_params_t *)params);
- data_source_init_floats(¶ms->DataSource, NULL, 0);/* client must set */
- /* Client must set BitsPerCoordinate and BitsPerComponent */
- /* if DataSource is not an array. */
- params->Decode = 0;
- params->Function = 0;
- }
-
- /* Allocate and initialize a shading. */
- /* Free variables: mem, params, ppsh, psh. */
- #define ALLOC_SHADING(sttype, stype, sprocs, cname)\
- BEGIN\
- psh = gs_alloc_struct(mem, void, sttype, cname);\
- if ( psh == 0 )\
- return_error(gs_error_VMerror);\
- psh->head.type = stype;\
- psh->head.procs = sprocs;\
- psh->params = *params;\
- *ppsh = (gs_shading_t *)psh;\
- END
-
- /* ---------------- Function-based shading ---------------- */
-
- private_st_shading_Fb();
-
- /* Initialize parameters for a Function-based shading. */
- void
- gs_shading_Fb_params_init(gs_shading_Fb_params_t * params)
- {
- shading_params_init((gs_shading_params_t *)params);
- params->Domain[0] = params->Domain[2] = 0;
- params->Domain[1] = params->Domain[3] = 1;
- gs_make_identity(¶ms->Matrix);
- params->Function = 0; /* must be set by client */
- }
-
- /* Allocate and initialize a Function-based shading. */
- private const gs_shading_procs_t shading_Fb_procs = {
- gs_shading_Fb_fill_rectangle
- };
- int
- gs_shading_Fb_init(gs_shading_t ** ppsh,
- const gs_shading_Fb_params_t * params, gs_memory_t * mem)
- {
- gs_shading_Fb_t *psh;
- gs_matrix imat;
- int code = check_CBFD((const gs_shading_params_t *)params,
- params->Function, params->Domain, 2);
-
- if (code < 0 ||
- (code = gs_matrix_invert(¶ms->Matrix, &imat)) < 0
- )
- return code;
- ALLOC_SHADING(&st_shading_Fb, shading_type_Function_based,
- shading_Fb_procs, "gs_shading_Fb_init");
- return 0;
- }
-
- /* ---------------- Axial shading ---------------- */
-
- private_st_shading_A();
-
- /* Initialize parameters for an Axial shading. */
- void
- gs_shading_A_params_init(gs_shading_A_params_t * params)
- {
- shading_params_init((gs_shading_params_t *)params);
- /* Coords must be set by client */
- params->Domain[0] = 0;
- params->Domain[1] = 1;
- params->Function = 0; /* must be set by client */
- params->Extend[0] = params->Extend[1] = false;
- }
-
- /* Allocate and initialize an Axial shading. */
- private const gs_shading_procs_t shading_A_procs = {
- gs_shading_A_fill_rectangle
- };
- int
- gs_shading_A_init(gs_shading_t ** ppsh,
- const gs_shading_A_params_t * params, gs_memory_t * mem)
- {
- gs_shading_A_t *psh;
- int code = check_CBFD((const gs_shading_params_t *)params,
- params->Function, params->Domain, 1);
-
- if (code < 0)
- return code;
- ALLOC_SHADING(&st_shading_A, shading_type_Axial,
- shading_A_procs, "gs_shading_A_init");
- return 0;
- }
-
- /* ---------------- Radial shading ---------------- */
-
- private_st_shading_R();
-
- /* Initialize parameters for a Radial shading. */
- void
- gs_shading_R_params_init(gs_shading_R_params_t * params)
- {
- shading_params_init((gs_shading_params_t *)params);
- /* Coords must be set by client */
- params->Domain[0] = 0;
- params->Domain[1] = 1;
- params->Function = 0; /* must be set by client */
- params->Extend[0] = params->Extend[1] = false;
- }
-
- /* Allocate and initialize a Radial shading. */
- private const gs_shading_procs_t shading_R_procs = {
- gs_shading_R_fill_rectangle
- };
- int
- gs_shading_R_init(gs_shading_t ** ppsh,
- const gs_shading_R_params_t * params, gs_memory_t * mem)
- {
- gs_shading_R_t *psh;
- int code = check_CBFD((const gs_shading_params_t *)params,
- params->Function, params->Domain, 1);
-
- if (code < 0)
- return code;
- if ((params->Domain != 0 && params->Domain[0] == params->Domain[1]) ||
- params->Coords[2] < 0 || params->Coords[5] < 0
- )
- return_error(gs_error_rangecheck);
- ALLOC_SHADING(&st_shading_R, shading_type_Radial,
- shading_R_procs, "gs_shading_R_init");
- return 0;
- }
-
- /* ---------------- Free-form Gouraud triangle mesh shading ---------------- */
-
- private_st_shading_FfGt();
-
- /* Initialize parameters for a Free-form Gouraud triangle mesh shading. */
- void
- gs_shading_FfGt_params_init(gs_shading_FfGt_params_t * params)
- {
- mesh_shading_params_init((gs_shading_mesh_params_t *)params);
- /* Client must set BitsPerFlag if DataSource is not an array. */
- }
-
- /* Allocate and initialize a Free-form Gouraud triangle mesh shading. */
- private const gs_shading_procs_t shading_FfGt_procs = {
- gs_shading_FfGt_fill_rectangle
- };
- int
- gs_shading_FfGt_init(gs_shading_t ** ppsh,
- const gs_shading_FfGt_params_t * params,
- gs_memory_t * mem)
- {
- gs_shading_FfGt_t *psh;
- int code = check_mesh((const gs_shading_mesh_params_t *)params);
- int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag);
-
- if (code < 0)
- return code;
- if (bpf < 0)
- return bpf;
- if (params->Decode != 0 && params->Decode[0] == params->Decode[1])
- return_error(gs_error_rangecheck);
- ALLOC_SHADING(&st_shading_FfGt, shading_type_Free_form_Gouraud_triangle,
- shading_FfGt_procs, "gs_shading_FfGt_init");
- psh->params.BitsPerFlag = bpf;
- return 0;
- }
-
- /* -------------- Lattice-form Gouraud triangle mesh shading -------------- */
-
- private_st_shading_LfGt();
-
- /* Initialize parameters for a Lattice-form Gouraud triangle mesh shading. */
- void
- gs_shading_LfGt_params_init(gs_shading_LfGt_params_t * params)
- {
- mesh_shading_params_init((gs_shading_mesh_params_t *)params);
- /* Client must set VerticesPerRow. */
- }
-
- /* Allocate and initialize a Lattice-form Gouraud triangle mesh shading. */
- private const gs_shading_procs_t shading_LfGt_procs = {
- gs_shading_LfGt_fill_rectangle
- };
- int
- gs_shading_LfGt_init(gs_shading_t ** ppsh,
- const gs_shading_LfGt_params_t * params, gs_memory_t * mem)
- {
- gs_shading_LfGt_t *psh;
- int code = check_mesh((const gs_shading_mesh_params_t *)params);
-
- if (code < 0)
- return code;
- if (params->VerticesPerRow < 2)
- return_error(gs_error_rangecheck);
- ALLOC_SHADING(&st_shading_LfGt, shading_type_Lattice_form_Gouraud_triangle,
- shading_LfGt_procs, "gs_shading_LfGt_init");
- return 0;
- }
-
- /* ---------------- Coons patch mesh shading ---------------- */
-
- private_st_shading_Cp();
-
- /* Initialize parameters for a Coons patch mesh shading. */
- void
- gs_shading_Cp_params_init(gs_shading_Cp_params_t * params)
- {
- mesh_shading_params_init((gs_shading_mesh_params_t *)params);
- /* Client must set BitsPerFlag if DataSource is not an array. */
- }
-
- /* Allocate and initialize a Coons patch mesh shading. */
- private const gs_shading_procs_t shading_Cp_procs = {
- gs_shading_Cp_fill_rectangle
- };
- int
- gs_shading_Cp_init(gs_shading_t ** ppsh,
- const gs_shading_Cp_params_t * params, gs_memory_t * mem)
- {
- gs_shading_Cp_t *psh;
- int code = check_mesh((const gs_shading_mesh_params_t *)params);
- int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag);
-
- if (code < 0)
- return code;
- if (bpf < 0)
- return bpf;
- ALLOC_SHADING(&st_shading_Cp, shading_type_Coons_patch,
- shading_Cp_procs, "gs_shading_Cp_init");
- psh->params.BitsPerFlag = bpf;
- return 0;
- }
-
- /* ---------------- Tensor product patch mesh shading ---------------- */
-
- private_st_shading_Tpp();
-
- /* Initialize parameters for a Tensor product patch mesh shading. */
- void
- gs_shading_Tpp_params_init(gs_shading_Tpp_params_t * params)
- {
- mesh_shading_params_init((gs_shading_mesh_params_t *)params);
- /* Client must set BitsPerFlag if DataSource is not an array. */
- }
-
- /* Allocate and initialize a Tensor product patch mesh shading. */
- private const gs_shading_procs_t shading_Tpp_procs = {
- gs_shading_Tpp_fill_rectangle
- };
- int
- gs_shading_Tpp_init(gs_shading_t ** ppsh,
- const gs_shading_Tpp_params_t * params, gs_memory_t * mem)
- {
- gs_shading_Tpp_t *psh;
- int code = check_mesh((const gs_shading_mesh_params_t *)params);
- int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag);
-
- if (code < 0)
- return code;
- if (bpf < 0)
- return bpf;
- ALLOC_SHADING(&st_shading_Tpp, shading_type_Tensor_product_patch,
- shading_Tpp_procs, "gs_shading_Tpp_init");
- psh->params.BitsPerFlag = bpf;
- return 0;
- }
-
- /* ================ Shading rendering ================ */
-
- /* Add a user-space rectangle to a path. */
- private int
- shading_path_add_box(gx_path *ppath, const gs_rect *pbox,
- const gs_matrix_fixed *pmat)
- {
- gs_fixed_point pt;
- gs_fixed_point pts[3];
- int code;
-
- if ((code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->p.y,
- &pt)) < 0 ||
- (code = gx_path_add_point(ppath, pt.x, pt.y)) < 0 ||
- (code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->p.y,
- &pts[0])) < 0 ||
- (code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->q.y,
- &pts[1])) < 0 ||
- (code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->q.y,
- &pts[2])) < 0 ||
- (code = gx_path_add_lines(ppath, pts, 3)) < 0
- )
- DO_NOTHING;
- return code;
- }
-
- /* Fill a path with a shading. */
- int
- gs_shading_fill_path(const gs_shading_t *psh, /*const*/ gx_path *ppath,
- const gs_fixed_rect *prect, gx_device *orig_dev,
- gs_imager_state *pis, bool fill_background)
- {
- gs_memory_t *mem = pis->memory;
- const gs_matrix_fixed *pmat = &pis->ctm;
- gx_device *dev = orig_dev;
- gs_fixed_rect path_box;
- gs_rect rect;
- gx_clip_path *path_clip = 0;
- bool path_clip_set = false;
- gx_device_clip path_dev;
- int code = 0;
-
- path_clip = gx_cpath_alloc(mem, "shading_fill_path(path_clip)");
- if (path_clip == 0) {
- code = gs_note_error(gs_error_VMerror);
- goto out;
- }
- dev_proc(dev, get_clipping_box)(dev, &path_box);
- if (prect)
- rect_intersect(path_box, *prect);
- if (psh->params.have_BBox) {
- gs_fixed_rect bbox_fixed;
-
- if ((is_xxyy(pmat) || is_xyyx(pmat)) &&
- (code = shade_bbox_transform2fixed(&psh->params.BBox, pis,
- &bbox_fixed)) >= 0
- ) {
- /* We can fold BBox into the clipping rectangle. */
- rect_intersect(path_box, bbox_fixed);
- } else
- {
- gx_path *box_path;
-
- if (path_box.p.x >= path_box.q.x || path_box.p.y >= path_box.q.y)
- goto out; /* empty rectangle */
- box_path = gx_path_alloc(mem, "shading_fill_path(box_path)");
- if (box_path == 0) {
- code = gs_note_error(gs_error_VMerror);
- goto out;
- }
- if ((code = gx_cpath_from_rectangle(path_clip, &path_box)) < 0 ||
- (code = shading_path_add_box(box_path, &psh->params.BBox,
- pmat)) < 0 ||
- (code = gx_cpath_intersect(path_clip, box_path,
- gx_rule_winding_number, pis)) < 0
- )
- DO_NOTHING;
- gx_path_free(box_path, "shading_fill_path(box_path)");
- if (code < 0)
- goto out;
- path_clip_set = true;
- }
- }
- if (!path_clip_set) {
- if (path_box.p.x >= path_box.q.x || path_box.p.y >= path_box.q.y)
- goto out; /* empty rectangle */
- if ((code = gx_cpath_from_rectangle(path_clip, &path_box)) < 0)
- goto out;
- }
- if (ppath &&
- (code =
- gx_cpath_intersect(path_clip, ppath, gx_rule_winding_number, pis)) < 0
- )
- goto out;
- gx_make_clip_device(&path_dev, &path_clip->rect_list->list);
- path_dev.target = dev;
- dev = (gx_device *)&path_dev;
- dev_proc(dev, open_device)(dev);
- dev_proc(dev, get_clipping_box)(dev, &path_box);
- if (psh->params.Background && fill_background) {
- int x0 = fixed2int(path_box.p.x);
- int y0 = fixed2int(path_box.p.y);
- int x1 = fixed2int(path_box.q.x);
- int y1 = fixed2int(path_box.q.y);
- const gs_color_space *pcs = psh->params.ColorSpace;
- gs_client_color cc;
- gx_device_color dev_color;
-
- cc = *psh->params.Background;
- (*pcs->type->restrict_color)(&cc, pcs);
- (*pcs->type->remap_color)(&cc, pcs, &dev_color, pis,
- dev, gs_color_select_texture);
- /****** WRONG IF NON-IDEMPOTENT RasterOp ******/
- code = gx_fill_rectangle_device_rop(x0, y0, x1 - x0, y1 - y0,
- &dev_color, dev, pis->log_op);
- if (code < 0)
- goto out;
- }
- {
- gs_rect path_rect;
-
- path_rect.p.x = fixed2float(path_box.p.x);
- path_rect.p.y = fixed2float(path_box.p.y);
- path_rect.q.x = fixed2float(path_box.q.x);
- path_rect.q.y = fixed2float(path_box.q.y);
- gs_bbox_transform_inverse(&path_rect, (const gs_matrix *)pmat, &rect);
- }
- code = gs_shading_fill_rectangle(psh, &rect, dev, pis);
- out:
- if (path_clip)
- gx_cpath_free(path_clip, "shading_fill_path(path_clip)");
- return code;
- }
-